package cn.nawang.ebeim.client.transfer;

import cn.nawang.ebeim.client.process.ProcessBar;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.URI;

public class TransferDownloadHandler extends SimpleChannelInboundHandler<HttpObject> {

    private static final Logger LOG = LoggerFactory.getLogger(TransferDownloadHandler.class);

    /**
     * 文件总长度
     */
    private long totalFileLength;

    /**
     * 已接收的文件长度
     */
    private long receiveTotal;

    private File file;// 临时文件名

    private RandomAccessFile randomFile;

    private TransferObject obj;

    private static final int MAX_PONG_TIMES = 30; // 定义客户端没有收到服务端的pong消息的最大次数

    private int pongTimes = 0;

    /**
     * 是否下载成功
     */
    private boolean isSuccess;

    private String errorMsg = "";

    private boolean isConnect;

    private TransferCallback callback;

    public TransferDownloadHandler(TransferObject obj, TransferCallback callback) {
        this.obj = obj;
        this.callback = callback;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        errorMsg = cause.getMessage();
        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                if (pongTimes >= MAX_PONG_TIMES) {
                    if(receiveTotal == totalFileLength&&file!=null){
                        IOUtils.closeQuietly(randomFile);
                        isSuccess = reNameFile(file);
                        ctx.close();
                    }else {
                        LOG.info("===客户端===(WRITER_IDLE 读超时)" + pongTimes);
                        isSuccess = false;
                        ctx.close();
                    }
                } else {
                    LOG.info("Got ping response for server:{},{},{}" ,ctx.channel().remoteAddress(), event.state(),pongTimes);
                    pongTimes++;
                }
            }
        }
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        LOG.info("channelUnregistered:{}",obj);
        IOUtils.closeQuietly(randomFile);
        if (!isConnect) {
            callback.onTransferFailed(obj, new TransferException("网络信号差,无法建立连接!"));
            return;
        }
        if (isSuccess) {
            callback.onTransferSuccess(obj);
        } else {
            callback.onTransferFailed(obj, new TransferException("文件下载失败!" + errorMsg));
        }
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        LOG.info("channelRegistered:{}",obj);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        isConnect = true;
        long downLength = 0;
        File file = getTempFile(obj);
        if (file.exists() && file.isFile()) {
            downLength = file.length();
        }
        QueryStringEncoder encoder = new QueryStringEncoder("download");
        encoder.addParam("dataId", obj.getDsId());
        encoder.addParam("signature", obj.getSignature());
        encoder.addParam("downLength", String.valueOf(downLength));
        URI uriGet = new URI(encoder.toString());
        String uri = TransferAuthService.encryptUrl(uriGet.toASCIIString());
        HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri);
        HttpHeaders headers = request.headers();
        headers.set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
        ctx.writeAndFlush(request);
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        pongTimes = 0;
        if (msg instanceof HttpResponse) {
            HttpResponse response = (HttpResponse) msg;
            if (HttpResponseStatus.OK.equals(response.getStatus())) {
                // 生成临时文件
                file = getTempFile(obj);
                LOG.info("开始下载:" + file.getAbsolutePath());
                totalFileLength = response.headers().getContentLength(response);
                //已完成下载
                if (totalFileLength == 0 && file.exists()) {
                    isSuccess = reNameFile(file);
                    ctx.close();
                } else {
                    randomFile = new RandomAccessFile(file, "rw");
                    long downLength = randomFile.length();
                    randomFile.seek(downLength);
                }
            } else {
                errorMsg = response.headers().get("error");
                isSuccess = false;
            }
        }

        if (msg instanceof HttpContent && totalFileLength != 0) {
            HttpContent chunk = (HttpContent) msg;
            ByteBuf buf = chunk.content();
            receiveTotal += buf.readableBytes();

            if(obj.getProcessBar()!=null){
                obj.getProcessBar().increaseRate(buf.readableBytes());
            }

            LOG.debug("下载进度：{}/{}", receiveTotal, totalFileLength);
            byte[] req = new byte[buf.readableBytes()];
            buf.readBytes(req);
            // 开始写入文件内容
            randomFile.write(req);
            if (chunk instanceof LastHttpContent) {
                if(receiveTotal == totalFileLength){
                    IOUtils.closeQuietly(randomFile);
                    isSuccess = reNameFile(file);
                }
            }
        }
    }

    private boolean reNameFile(File file) {
        //最终文件名
        String fileName = obj.getFilePath() + File.separator + obj.getSignature();
        File lastFile = new File(fileName) ;

        boolean boolFile = false;
        
        if (lastFile.exists()){
          if (lastFile.delete()) {
            boolFile = file.renameTo(lastFile);
          } 
        } else {
          boolFile = file.renameTo(lastFile);
        }
        
        if (boolFile) {
          LOG.info("客户端已成功下载文件，保存路径：" + lastFile.getPath());
        } else {
          boolean delete = file.delete();
          errorMsg = "重命名失败，文件名,删除：" + file + " : " + delete;
        }
        
        return boolFile;
    }

    private static File getTempFile(TransferObject obj) {
        String filePath = obj.getFilePath() + File.separator + "temp_file_" + obj.getSignature();
        File tempFile = new File(filePath);
        if (!tempFile.getParentFile().exists()) {
            tempFile.getParentFile().mkdirs();
        }
        return tempFile;
    }



}
